home *** CD-ROM | disk | FTP | other *** search
-
- /* Generated by Interface Builder */
-
- #import "LyapunovView.h"
- #import <math.h>
- #import <appkit/tiff.h>
- #import <appkit/color.h>
- #import <appkit/graphics.h>
- #import <appkit/Control.h>
- #import <appkit/Matrix.h>
- #import <appkit/NXColorWell.h>
- #import <dpsclient/psops.h>
- #import <appkit/Application.h>
- #import <dpsclient/psops.h>
- #import <dpsclient/wraps.h>
-
-
- @implementation LyapunovView
-
- - initFrame:(const NXRect *)frm // designated initializer for a view
- {
- [super initFrame:frm];
- return self;
- }
-
- - appDidInit:sender // final initialization
- {
- // set up default colors
- fromColor = NXConvertRGBToColor(1.0, 1.0, 0.0);
- toColor = NXConvertRGBToColor(0.01, 0.01, 0.0);
- backColor = NXConvertRGBToColor(0.0, 0.0, 0.05);
- [fromShade setColor:fromColor];
- [toShade setColor:toColor];
- [backShade setColor:backColor];
-
- // set up plot type
- singleDot = NO;
- [plotType selectCellWithTag:singleDot];
-
- // set up default position
- xPos = 0.0; yPos = 0.0;
- [[posMatrix findCellWithTag:0] setFloatValue:xPos];
- [[posMatrix findCellWithTag:1] setFloatValue:yPos];
-
- // set up default scale
- xScale = 1.0; yScale = 1.0;
- [[scaleMatrix findCellWithTag:0] setFloatValue:xScale];
- [[scaleMatrix findCellWithTag:1] setFloatValue:yScale];
-
- // set up default initial value
- initial = 0.1;
- [[initialValue findCellWithTag:0] setFloatValue:initial];
-
- // set up default depth
- deep = 4000;
- [[depth findCellWithTag:0] setIntValue:deep];
-
- // set up default pattern
- [[pattern findCellWithTag:0] setStringValue:"ab"];
-
- // set up contrast
- [contrastText setFloatValue:2.0];
- [contrastSlider setFloatValue:2.0];
-
- return self;
- }
-
- - contrast:sender // adjust image contrast coeff
- {
- contrast = [sender floatValue];
- [contrastText setFloatValue:contrast];
- [contrastSlider setFloatValue:contrast];
-
- return self;
- }
-
- - go:sender // begin calculation of image
- {
- register float total, t, tNew, r, a, b, expSum;
- float spMul, rb, gb, bb, rd, gd, bd, rk, gk, bk;
- register int ndx, x, n, pix, y, avgCnt;
- NXRect pixel, line;
- float log2 = log(2);
-
- pixel.size.width = 1;
- pixel.size.height = 1;
- line.size.height = 1;
- line.size.width = XSIZE;
- line.origin.x = 0;
-
- [self newParam:self]; // be sure we're up to date
-
- // set up color constants
- rb = NXRedComponent(fromColor);
- gb = NXGreenComponent(fromColor);
- bb = NXBlueComponent(fromColor);
- rd = NXRedComponent(toColor) - rb;
- gd = NXGreenComponent(toColor) - gb;
- bd = NXBlueComponent(toColor) - bb;
- rk = NXRedComponent(backColor);
- gk = NXGreenComponent(backColor);
- bk = NXBlueComponent(backColor);
-
- // main calc loop: calc line & draw it.
- expSum = 0; avgCnt = 0;
- [self lockFocus];
- for (y=0; y<YSIZE; y++) {
- b = yPos + y*yScale/YSIZE; // get physical y-coord
- for (x=0; x<XSIZE; x++) {
- a = xPos + x*xScale/XSIZE; // get physical x-coord
- total = 0.0; t = initial; ndx = 0;
- for (n=0; n<deep; n++) {
- r = (patternNum[ndx] ? a : b);
- tNew = t * (1 - t) * r;
- ndx++;
- if (ndx >= patternLength) ndx = 0;
- total += log(fabs(r - 2 * r * tNew)) / log2;
- t = tNew;
- }
- space[x][y] = total / deep; // Lyapunov exponent approx.
- // put into pixel map w/color
- pix = (x+(YSIZE-y-1)*XSIZE)*RGB;
- if (total >= 0) {
- pixels[pix] = 255 * rk; // pix+RED = pix because RED=0
- pixels[pix+GREEN] = 255 * gk;
- pixels[pix+BLUE] = 255 * bk;
- space[x][y] = 0;
- } else { // no chaos, so color it
- spMul = fabs(space[x][y]/contrast); // scale into color map
- if (spMul > 1.0) spMul = 1.0;
- if (fabs(space[x][y]) < 100000.0) {
- expSum += space[x][y];
- avgCnt++;
- }
- pixels[pix] = 255 *(spMul * rd + rb);
- pixels[pix+GREEN]= 255*(spMul * gd + gb);
- pixels[pix+BLUE] = 255*(spMul * bd + bb);
- }
- if (singleDot) {
- // plot a pixel of it
- pixel.origin.x = x;
- pixel.origin.y = y;
- NXImageBitmap(&pixel, 1, 1, 8, 3,
- NX_MESHED, NX_COLORMASK,
- &pixels[(x+(YSIZE-y-1)*XSIZE)*RGB],
- NULL, NULL, NULL, NULL);
- [window flushWindow];
- NXPing();
- }
- }
- if (!singleDot) {
- // plot a line of it
- line.origin.y = y;
- NXImageBitmap(&line, XSIZE, 1, 8, 3,
- NX_MESHED, NX_COLORMASK, &pixels[(YSIZE-y-1)*XSIZE*RGB],
- NULL, NULL, NULL, NULL);
- [window flushWindow];
- NXPing();
- }
- }
- [self unlockFocus];
- [avgOut setFloatValue:(expSum/avgCnt)];
- [reApplyButton setEnabled:YES];
- return self;
- }
-
- - reApply:sender // re do coloring on plot
- {
- register int x, y, pix;
- float rb, gb, bb, rd, gd, bd, rk, gk, bk;
- float spMul;
- NXRect pixel, line;
-
- [self newParam:self]; // be sure we're up to date
- // set up plotting bounds
- pixel.size.width = 1; pixel.size.height = 1;
- line.size.height = 1; line.size.width = XSIZE;
- line.origin.x = 0;
- // get color params
- rb = NXRedComponent(fromColor); gb = NXGreenComponent(fromColor);
- bb = NXBlueComponent(fromColor); rd = NXRedComponent(toColor) - rb;
- gd = NXGreenComponent(toColor) - gb; bd = NXBlueComponent(toColor) - bb;
- rk = NXRedComponent(backColor); gk = NXGreenComponent(backColor);
- bk = NXBlueComponent(backColor);
- // re-apply colors
- [self lockFocus];
- for (y=0; y<YSIZE; y++) {
- for (x=0; x<XSIZE; x++) {
- pix = (x+(YSIZE-y-1)*XSIZE)*RGB;
- if (space[x][y] >= 0) {
- pixels[pix] = 255 * rk; // pix+RED = pix because RED=0
- pixels[pix+GREEN] = 255 * gk;
- pixels[pix+BLUE] = 255 * bk;
- } else { // no chaos, so color it
- spMul = fabs(space[x][y]/contrast); // scale into color map
- if (spMul > 1.0) spMul = 1.0;
- pixels[pix] = 255 *(spMul * rd + rb);
- pixels[pix+GREEN]= 255*(spMul * gd + gb);
- pixels[pix+BLUE] = 255*(spMul * bd + bb);
- }
- }
- // plot a line of it
- line.origin.y = y;
- NXImageBitmap(&line, XSIZE, 1, 8, 3,
- NX_MESHED, NX_COLORMASK, &pixels[(YSIZE-y-1)*XSIZE*RGB],
- NULL, NULL, NULL, NULL);
- [window flushWindow];
- NXPing();
- }
- [self unlockFocus];
- return self;
- }
-
- - newParam:sender // set up new parameters for calc
- {
- int count;
-
- // get colors
- fromColor = [fromShade color];
- toColor = [toShade color];
- backColor = [backShade color];
-
- // get plotting method (dots or lines)
- singleDot = [[plotType selectedCell] tag];
-
- // get x-y coordinates
- xPos = [[posMatrix findCellWithTag:0] floatValue];
- yPos = [[posMatrix findCellWithTag:1] floatValue];
-
- // get x-y scaling
- xScale = [[scaleMatrix findCellWithTag:0] floatValue];
- yScale = [[scaleMatrix findCellWithTag:1] floatValue];
-
- // get initial value for each point
- initial = [[initialValue findCellWithTag:0] floatValue];
-
- // get depth
- deep = [[depth findCellWithTag:0] intValue];
-
- // get pattern
- patternString = [[pattern findCellWithTag:0] stringValue];
- for(count=0; patternString[count]!='\0'; count++) {
- patternNum[count] = ((patternString[count]=='a') ? 0 : 1);
- }
- patternLength = count;
- return self;
- }
-
- - drawSelf:(NXRect *)rects :(int)rectCount // redraws the screen.
- {
- PSsetgray(NX_DKGRAY);
- NXRectFill(&bounds);
- return self;
- }
-
- - mouseDown:(NXEvent *)e // stolen from MandelView.m
- /*
- * We implement the mouseDown method so the user can sweep out a section of
- * the view and select that as the current x,y,scale coordinates.
- */
- {
- int looping = YES;
- int oldMask;
- NXRect bbox;
- NXPoint startPoint, currPoint;
- double newX, newY, newDX, newDY;
- NXCoord aspectRatio;
- float mvX = xPos;
- float mvY = yPos;
- float mvDX = xScale;
- float mvDY = yScale;
-
- aspectRatio = bounds.size.height / bounds.size.width;
-
- oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
- startPoint = e->location;
- [self convertPoint:&startPoint fromView:nil];
- NXSetRect(&bbox,startPoint.x,startPoint.y,0.0,0.0);
- [self lockFocus];
- while (looping) {
- e=[NXApp getNextEvent:NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK];
- currPoint = e->location;
- [self convertPoint:&currPoint fromView:nil];
- bbox.size.width = 2*(currPoint.x - startPoint.x);
- bbox.size.height = 2*(currPoint.y - startPoint.y);
- /* Normalize bbox to always have positive width and height */
- if (bbox.size.width < 0) bbox.size.width = -bbox.size.width;
- if (bbox.size.height < 0) bbox.size.height = -bbox.size.height;
- /*
- * constrain the box to have the aspect ratio of the view. Choose
- * whichever dimension is closer to the desired result.
- */
- if ((bbox.size.height/bbox.size.width) > aspectRatio) {
- bbox.size.height = bbox.size.width * aspectRatio;
- } else {
- bbox.size.width = bbox.size.height / aspectRatio;
- }
- /* The startPoint is always at the center of the bbox */
- bbox.origin.x = startPoint.x - .5 * bbox.size.width;
- bbox.origin.y = startPoint.y - .5 * bbox.size.height;
- PSnewinstance();
- if (looping = (e->type == NX_MOUSEDRAGGED)) {
- PSsetinstance(YES);
- PSsetgray(NX_WHITE);
- NXFrameRect(&bbox);
- PSsetinstance(NO);
- }
- }
- [self unlockFocus];
- [window setEventMask:oldMask];
- if ((bbox.size.width > 0) && (bbox.size.height > 0)) {
- /*
- * At this point, bbox is in window coordinates. Set new controller
- * parameters based on this view's coordinates and the bounding box.
- */
- newDX = (bbox.size.width*mvDX)/bounds.size.width;
- newDY = (bbox.size.height*mvDY)/bounds.size.height;
- newX = ((startPoint.x + bounds.origin.x) / bounds.size.width);
- newX = newX * mvDX + mvX - newDX/2;
- newY = ((startPoint.y + bounds.origin.y) / bounds.size.height);
- newY = newY * mvDY + mvY - newDY/2;
-
- /*
- * Note that we only update the text fields -- we
- * don't update the internal instance variables. If we were to update
- * the internal ivs, then the user would only get one chance with the
- * mouse down method because subsequent mouse-downs would work in terms
- * of the new coordinate system.
- */
- [[posMatrix findCellWithTag:0] setFloatValue:newX];
- [[posMatrix findCellWithTag:1] setFloatValue:newY];
- [[scaleMatrix findCellWithTag:0] setFloatValue:newDX];
- [[scaleMatrix findCellWithTag:1] setFloatValue:newDY];
- }
- return self;
- }
-
- @end
-